﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace AllenalaMente.Games.Flux
{
    public enum Direction
    {
        Right,
        Down,
        Left,
        Up
    }

    public class Coordinates
    {
        public int X;
        public int Y;
        public Direction BeamOut;
        public Direction BeamIn;
    }

    public partial class Flux : UserControl, GameInterface
    {
        private DispatcherTimer startTimer;
        private TimeSpan startTime;
        private Random random;
        //private List<Coordinates> directionChanges;
        private List<Tile> mirrors;
        private Tile startingTile;
        private int score, numTiles, gameDifficulty, floorRows, floorColumns, correctAnswers, wrongAnswers;
        private UITimer UIgameTimer;
        private UIScore UIgameScore;
        private Tile[,] tiles = new Tile[8, 13];
        private bool isSchemaValid = false;
        //private List<Rectangle> beamRectangles;

        public Flux()
        {
            InitializeComponent();

            // Initialize game
            random = new Random();
            score = 0;
            correctAnswers = 0;
            wrongAnswers = 0;
            gameDifficulty = 0;

            floorColumns = gridFloor.ColumnDefinitions.Count;
            floorRows = gridFloor.RowDefinitions.Count;
            numTiles = floorColumns * floorRows;

            // Initialize floor tiles
            for (int i = 0; i < numTiles; i++)
            {
                int row = i / floorColumns;
                int column = i % floorColumns;
                Coordinates coords = new Coordinates() { X = column, Y = row };

                Tile tile = new Tile("/AllenalaMente;component/Assets/Images/FloorTiles/floorTile0" + random.Next(1, 7) + ".jpg", coords);
                tiles[row, column] = tile;
                tile.Opacity = 0.8;
                Grid.SetRow(tile, row);
                Grid.SetColumn(tile, column);
                gridFloor.Children.Add(tile);
            }

            mirrors = new List<Tile>();

            // Start timer
            startTimer = new DispatcherTimer();
            startTimer.Interval = TimeSpan.FromMilliseconds(600);
            startTimer.Tick += new EventHandler(startTimer_Tick);
            startTimer.Start();
            startTime = TimeSpan.FromSeconds(3);
            TextBlockReady.Text = Locale.Strings.Ready;

            // UI Game timer
            UIgameTimer = new UITimer(90);
            LayoutRoot.Children.Add(UIgameTimer);
            UIgameTimer.timeOut += new EventHandler(game_TimeOut);

            // UI Game Score
            UIgameScore = new UIScore();
            LayoutRoot.Children.Add(UIgameScore);
            Canvas.SetLeft(UIgameScore, 750);
        }


        #region Metodi

        private void GenerateSchema()
        {
            mirrors.Clear();

            // Ripulisce la lista delle tiles
            for (int i = 0; i < tiles.Length; i++)
            {
                int row = i / floorColumns;
                int column = i % floorColumns;
                tiles[row, column].imageMirror.Visibility = System.Windows.Visibility.Collapsed;
                tiles[row, column].IsTouched = false;
                tiles[row, column].Type = TileType.Empty;
                tiles[row, column].HideBeams();
            }

            // Prima di tutto estraggo il numero di cambi di direzione in base alla difficolta'
            int maxChanges = 2 + (gameDifficulty * 2);
            //int directionChanges = random.Next(maxChanges + 1);
            int changesNumber = maxChanges;

            // Poi estraggo un punto di partenza del flusso
            int startingRow = random.Next(floorRows);
            startingTile = tiles[startingRow, 0];
            startingTile.IsTouched = true;
            startingTile.Type = TileType.Beam;
            startingTile.Coordinates.BeamOut = Direction.Right;
            startingTile.Coordinates.BeamIn = Direction.Left;

            for (int i = 0; i < changesNumber; i++)
            {
                // Specchio precedente
                Tile previousMirror;
                if (mirrors.Count == 0)
                    previousMirror = startingTile;
                else
                    previousMirror = mirrors.Last();

                // Decido di quante caselle procedere prima di cambiare direzione
                Coordinates lastCoords = previousMirror.Coordinates;
                Tile chosenTile = new Tile();
                if (lastCoords.BeamOut == Direction.Right || lastCoords.BeamOut == Direction.Left)
                {
                    // Sto procedendo in orizzontale
                    int currentRow = lastCoords.Y;

                    // Tiles a sinistra della posizione attuale
                    List<Tile> leftEligibleTiles = GetTilesToNextMirror(lastCoords.X, lastCoords.Y, Direction.Left);

                    // Tiles a destra della posizione attuale
                    List<Tile> rightEligibleTiles = GetTilesToNextMirror(lastCoords.X, lastCoords.Y, Direction.Right);

                    // Se non ci sono mosse possibili invalida lo schema
                    if (leftEligibleTiles.Count == 0 && rightEligibleTiles.Count == 0)
                    {
                        isSchemaValid = false;
                        return;
                    }

                    // Decide di andare dove ci sono piu' tiles a disposizione
                    if (leftEligibleTiles.Count > rightEligibleTiles.Count)
                        lastCoords.BeamOut = Direction.Left;
                    else
                        lastCoords.BeamOut = Direction.Right;

                    // Ora estrae la casella per il prossimo passo
                    Coordinates chosenTileCoords = new Coordinates();
                    if (lastCoords.BeamOut == Direction.Right)
                    {
                        // Verso destra
                        chosenTile = rightEligibleTiles[random.Next(rightEligibleTiles.Count)];

                        // Memorizzo i tile coinvolti
                        chosenTile.IsTouched = true;
                        chosenTile.Type = TileType.Mirror;
                        chosenTile.Coordinates.BeamIn = Direction.Left;

                        for (int j = 0; j < rightEligibleTiles.Count; j++)
                        {
                            if (rightEligibleTiles[j].Coordinates.X < chosenTile.Coordinates.X)
                            {
                                // Se ci sono mirror nel mezzo, invalida lo schema
                                if (rightEligibleTiles[j].IsTouched && rightEligibleTiles[j].Type == TileType.Mirror)
                                {
                                    isSchemaValid = false;
                                    return;
                                }
                                rightEligibleTiles[j].IsTouched = true;
                                rightEligibleTiles[j].Type = TileType.Beam;
                                rightEligibleTiles[j].Coordinates.BeamOut = Direction.Right;
                                rightEligibleTiles[j].Coordinates.BeamIn = Direction.Left;
                            }
                            else
                                break;
                        }
                    }
                    else if (lastCoords.BeamOut == Direction.Left)
                    {
                        // Verso sinistra
                        chosenTile = leftEligibleTiles[random.Next(leftEligibleTiles.Count)];

                        // Memorizzo i tile coinvolti
                        chosenTile.IsTouched = true;
                        chosenTile.Type = TileType.Mirror;
                        chosenTile.Coordinates.BeamIn = Direction.Right;

                        for (int j = leftEligibleTiles.Count - 1; j > 0; j--)
                        {
                            if (leftEligibleTiles[j].Coordinates.X > chosenTile.Coordinates.X)
                            {
                                // Se ci sono mirror nel mezzo, invalida lo schema
                                if (leftEligibleTiles[j].IsTouched && leftEligibleTiles[j].Type == TileType.Mirror)
                                {
                                    isSchemaValid = false;
                                    return;
                                }
                                leftEligibleTiles[j].IsTouched = true;
                                leftEligibleTiles[j].Type = TileType.Beam;
                                leftEligibleTiles[j].Coordinates.BeamOut = Direction.Left;
                                leftEligibleTiles[j].Coordinates.BeamIn = Direction.Right;
                            }
                            else
                                break;
                        }
                    }

                    // Solo per indicare che al prossimo step andro' in verticale
                    chosenTile.Coordinates.BeamOut = Direction.Down;
                }
                else
                {
                    // Sto procedendo in verticale
                    int currentColumn = lastCoords.X;

                    // Tiles sopra la posizione attuale
                    List<Tile> upperEligibleTiles = GetTilesToNextMirror(lastCoords.X, lastCoords.Y, Direction.Up);

                    // Tiles sotto la posizione attuale
                    List<Tile> lowerEligibleTiles = GetTilesToNextMirror(lastCoords.X, lastCoords.Y, Direction.Down);

                    // Se non ci sono mosse possibili invalida lo schema
                    if (upperEligibleTiles.Count == 0 && lowerEligibleTiles.Count == 0)
                    {
                        isSchemaValid = false;
                        return;
                    }

                    // Decide di andare dove ci sono piu' tiles a disposizione
                    if (upperEligibleTiles.Count > lowerEligibleTiles.Count)
                        lastCoords.BeamOut = Direction.Up;
                    else
                        lastCoords.BeamOut = Direction.Down;

                    // Ora estrae la casella per il prossimo passo
                    Coordinates chosenTileCoords = new Coordinates();
                    if (lastCoords.BeamOut == Direction.Down)
                    {
                        // Verso il basso
                        chosenTile = lowerEligibleTiles[random.Next(lowerEligibleTiles.Count)];

                        // Memorizzo i tile coinvolti
                        chosenTile.IsTouched = true;
                        chosenTile.Type = TileType.Mirror;
                        chosenTile.Coordinates.BeamIn = Direction.Up;

                        for (int j = 0; j < lowerEligibleTiles.Count; j++)
                        {
                            if (lowerEligibleTiles[j].Coordinates.Y < chosenTile.Coordinates.Y)
                            {
                                // Se ci sono mirror nel mezzo, invalida lo schema
                                if (lowerEligibleTiles[j].IsTouched && lowerEligibleTiles[j].Type == TileType.Mirror)
                                {
                                    isSchemaValid = false;
                                    return;
                                }
                                lowerEligibleTiles[j].IsTouched = true;
                                lowerEligibleTiles[j].Type = TileType.Beam;
                                lowerEligibleTiles[j].Coordinates.BeamOut = Direction.Down;
                                lowerEligibleTiles[j].Coordinates.BeamIn = Direction.Up;
                            }
                            else
                                break;
                        }
                    }
                    else if (lastCoords.BeamOut == Direction.Up)
                    {
                        // Verso l'alto
                        chosenTile = upperEligibleTiles[random.Next(upperEligibleTiles.Count)];

                        // Memorizzo i tile coinvolti
                        chosenTile.IsTouched = true;
                        chosenTile.Type = TileType.Mirror;
                        chosenTile.Coordinates.BeamIn = Direction.Down;

                        for (int j = upperEligibleTiles.Count - 1; j > 0; j--)
                        {
                            if (upperEligibleTiles[j].Coordinates.Y > chosenTile.Coordinates.Y)
                            {
                                // Se ci sono mirror nel mezzo, invalida lo schema
                                if (upperEligibleTiles[j].IsTouched && upperEligibleTiles[j].Type == TileType.Mirror)
                                {
                                    isSchemaValid = false;
                                    return;
                                }
                                upperEligibleTiles[j].IsTouched = true;
                                upperEligibleTiles[j].Type = TileType.Beam;
                                upperEligibleTiles[j].Coordinates.BeamOut = Direction.Up;
                                upperEligibleTiles[j].Coordinates.BeamIn = Direction.Down;
                            }
                            else
                                break;
                        }
                    }

                    // Solo per indicare che al prossimo step andro' in orizzontale
                    chosenTile.Coordinates.BeamOut = Direction.Right;
                }

                mirrors.Add(chosenTile);
            }

            // Sistema l'ultima parte del raggio
            // Tiles a destra dell'ultimo specchio
            List<Tile> lastTiles = new List<Tile>();
            Coordinates lastMirrorCoords = mirrors.Last().Coordinates;
            for (int j = lastMirrorCoords.X + 1; j < floorColumns; j++)
            {
                Tile currTile = tiles[lastMirrorCoords.Y, j];
                // Invalida lo schema se ci sono specchi nell'ultima parte del raggio
                if (currTile.IsTouched && currTile.Type == TileType.Mirror)
                {
                    isSchemaValid = false;
                    return;
                }
                currTile.IsTouched = true;
                currTile.Type = TileType.Beam;
                currTile.Coordinates.BeamIn = Direction.Left;
                currTile.Coordinates.BeamOut = Direction.Right;
            }

            isSchemaValid = true;
        }

        /// <summary>
        /// Torna la lista delle Tile partendo da delle coordinate verso una specifica direzione, fino ad incontrare uno specchio
        /// </summary>
        /// <param name="X">La X della coordinata di partenza</param>
        /// <param name="Y">La Y della coordinata di partenza</param>
        /// <param name="direction">La direzione verso cui procedere</param>
        /// <returns>La lista di Tile</returns>
        private List<Tile> GetTilesToNextMirror(int X, int Y, Direction direction, bool includeTouched = false)
        {
            List<Tile> tilesToMirror = new List<Tile>();
            int iterationStart = 0;
            int iterationEnd = 0;
            switch (direction)
            {
                case Direction.Right:
                    iterationStart = X + 1;
                    iterationEnd = floorColumns;
                    break;
                case Direction.Down:
                    iterationStart = Y + 1;
                    iterationEnd = floorRows;
                    break;
                case Direction.Left:
                    iterationStart = 0;
                    iterationEnd = X;
                    break;
                case Direction.Up:
                    iterationStart = 0;
                    iterationEnd = Y;
                    break;
            }

            for (int j = iterationStart; j < iterationEnd; j++)
            {
                Tile currTile = null;
                if (direction == Direction.Up || direction == Direction.Down)
                    currTile = tiles[j, X];
                else  // Direction is left or right
                    currTile = tiles[Y, j];

                if (currTile.IsTouched)
                {
                    if (currTile.Type == TileType.Mirror)
                        break;
                    if (includeTouched)
                        tilesToMirror.Add(currTile);
                }
                else
                    tilesToMirror.Add(currTile);
            }

            return tilesToMirror;
        }


        private void PrepareMirrors()
        {
            mirrors[0].correctAngle = CalculateMirrorRotation(Direction.Right, mirrors[0].Coordinates.BeamOut);
            mirrors[0].ShowMirror(90 * random.Next(4));

            for (int i = 1; i < mirrors.Count; i++)
            {
                Direction inDirection = mirrors[i - 1].Coordinates.BeamOut;
                Direction outDirection = mirrors[i].Coordinates.BeamOut;

                mirrors[i].correctAngle = CalculateMirrorRotation(inDirection, outDirection);
                mirrors[i].ShowMirror(90 * random.Next(4));
            }
        }

        /// <summary>
        /// Given in and out flux directions, returns the angle the mirror should be rotated to
        /// </summary>
        /// <param name="inDirection">The entry direction of the beam in the mirror</param>
        /// <param name="outDirection">The exit direction of the beam from the mirror</param>
        /// <returns>The angle the mirror should be rotated to</returns>
        private int CalculateMirrorRotation(Direction inDirection, Direction outDirection)
        {
            switch (inDirection)
            {
                case Direction.Right:
                    if (outDirection == Direction.Down)
                        return 90;
                    if (outDirection == Direction.Up)
                        return 180;
                    break;
                case Direction.Down:
                    if (outDirection == Direction.Right)
                        return 270;
                    if (outDirection == Direction.Left)
                        return 180;
                    break;
                case Direction.Left:
                    if (outDirection == Direction.Down)
                        return 0;
                    if (outDirection == Direction.Up)
                        return 270;
                    break;
                case Direction.Up:
                    if (outDirection == Direction.Right)
                        return 0;
                    if (outDirection == Direction.Left)
                        return 90;
                    break;
                default:
                    break;
            }

            return 0;
        }

        private void PrepareBeamers()
        {
            // Initialize start beamer
            //Canvas.SetLeft(imageBeamStart, Canvas.GetLeft(gridFloor) - imageBeamStart.Width);
            Canvas.SetTop(imageBeamStart, Canvas.GetTop(gridFloor) + (tiles[0, 0].imageFloorTile.Height * mirrors[0].Coordinates.Y));
            Uri uri = new Uri("/AllenalaMente;component/Assets/Images/Flux/LaserGun.png", UriKind.RelativeOrAbsolute);
            ImageSource img = new System.Windows.Media.Imaging.BitmapImage(uri);
            imageBeamStart.SetValue(Image.SourceProperty, img);
            imageBeamStart.MouseLeftButtonDown += new MouseButtonEventHandler(imageBeamStart_MouseLeftButtonDown);

            // Initialize end beamer
            //Canvas.SetLeft(imageBeamEnd, Canvas.GetLeft(gridFloor) + gridFloor.Width);
            Canvas.SetTop(imageBeamEnd, Canvas.GetTop(gridFloor) + (tiles[0, 0].imageFloorTile.Height * mirrors.Last().Coordinates.Y));
            uri = new Uri("/AllenalaMente;component/Assets/Images/Flux/Spot.png", UriKind.RelativeOrAbsolute);
            img = new System.Windows.Media.Imaging.BitmapImage(uri);
            imageBeamEnd.SetValue(Image.SourceProperty, img);

            // Initialize arrow
            Canvas.SetLeft(imageArrowDown, Canvas.GetLeft(imageBeamStart) + 10);
            Canvas.SetTop(imageArrowDown, Canvas.GetTop(imageBeamStart) - imageArrowDown.Height);
            uri = new Uri("/AllenalaMente;component/Assets/Images/Flux/arrowDown.png", UriKind.RelativeOrAbsolute);
            img = new System.Windows.Media.Imaging.BitmapImage(uri);
            imageArrowDown.SetValue(Image.SourceProperty, img);

            imageArrowDown.RenderTransform = new TranslateTransform();
            Storyboard sb = new Storyboard();
            DoubleAnimation upDownAnimation = new DoubleAnimation() { AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever };
            upDownAnimation.Duration = TimeSpan.FromSeconds(0.5);
            upDownAnimation.From = 0;
            upDownAnimation.To = -30;
            upDownAnimation.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
            sb.Children.Add(upDownAnimation);
            Storyboard.SetTarget(upDownAnimation, imageArrowDown);
            Storyboard.SetTargetProperty(upDownAnimation, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)"));
            sb.Begin();
        }


        private void IncreaseScore(int amount)
        {
            score += amount;
            UIgameScore.SetScore(score);
        }

        /// <summary>
        /// Draw a flux with a specified color, following the correct or wrong direction
        /// </summary>
        /// <param name="color">The color to draw the flux with</param>
        /// <param name="followCorrect">True to follow the direction given by the mirrors, false otherwise</param>
        private void DrawFlux(Color color, bool followCorrect = false)
        {
            // Draw flux with the specified color
            startingTile.DrawBeam(startingTile.Coordinates.BeamIn, startingTile.Coordinates.BeamOut, color);

            Tile currentTile = startingTile;

            Direction previousDirection = currentTile.Coordinates.BeamOut;
            Direction newDirection = Direction.Right;
            bool stop = false;
            while (!stop)
            {
                if (currentTile.Type == TileType.Mirror)
                {
                    // When a mirror is found, the wrong or the correct direction can be followed, depending on the boolean followCorrect
                    int angleToFollow = (int)currentTile.rotateTransform.Angle;
                    if (followCorrect)
                        angleToFollow = currentTile.correctAngle;
                    switch (angleToFollow)
                    {
                        case 0:
                            if (currentTile.Coordinates.BeamIn == Direction.Right)
                                newDirection = Direction.Down;
                            else if (currentTile.Coordinates.BeamIn == Direction.Down)
                                newDirection = Direction.Right;
                            else
                            {
                                // If this mirror is rotated in other directions, stop drawing
                                stop = true;
                                continue;
                            }
                            break;
                        case 90:
                            if (currentTile.Coordinates.BeamIn == Direction.Left)
                                newDirection = Direction.Down;
                            else if (currentTile.Coordinates.BeamIn == Direction.Down)
                                newDirection = Direction.Left;
                            else
                            {
                                // If this mirror is rotated in other directions, stop drawing
                                stop = true;
                                continue;
                            }
                            break;
                        case 180:
                            if (currentTile.Coordinates.BeamIn == Direction.Left)
                                newDirection = Direction.Up;
                            else if (currentTile.Coordinates.BeamIn == Direction.Up)
                                newDirection = Direction.Left;
                            else
                            {
                                // If this mirror is rotated in other directions, stop drawing
                                stop = true;
                                continue;
                            }
                            break;
                        case 270:
                            if (currentTile.Coordinates.BeamIn == Direction.Right)
                                newDirection = Direction.Up;
                            else if (currentTile.Coordinates.BeamIn == Direction.Up)
                                newDirection = Direction.Right;
                            else
                            {
                                // If this mirror is rotated in other directions, stop drawing
                                stop = true;
                                continue;
                            }
                            break;
                    }
                    currentTile.DrawBeam(currentTile.Coordinates.BeamIn, newDirection, color);
                }
                else
                {
                    // When a Beam or Empty tile type is found, follow the flux depending on the exit direction
                    switch (newDirection)
                    {
                        case Direction.Right:
                            previousDirection = Direction.Left;
                            break;
                        case Direction.Down:
                            previousDirection = Direction.Up;
                            break;
                        case Direction.Left:
                            previousDirection = Direction.Right;
                            break;
                        case Direction.Up:
                            previousDirection = Direction.Down;
                            break;
                    }
                    currentTile.DrawBeam(previousDirection, newDirection, color);
                }

                // Calculate next tile position depending on the current tile exit direction
                int nextTileY = currentTile.Coordinates.X;
                int nextTileX = currentTile.Coordinates.Y;

                switch (newDirection)
                {
                    case Direction.Right:
                        nextTileY += 1;
                        break;
                    case Direction.Down:
                        nextTileX += 1;
                        break;
                    case Direction.Left:
                        nextTileY -= 1;
                        break;
                    case Direction.Up:
                        nextTileX -= 1;
                        break;
                }

                // If we're off the array, stop drawing
                if (nextTileX < 0 || nextTileX >= floorRows)
                    break;
                if (nextTileY < 0 || nextTileY >= floorColumns)
                    break;

                // Otherwise, extract new tile and continue with the cycle
                currentTile = tiles[nextTileX, nextTileY];
                previousDirection = newDirection;
            }
        }


        #endregion


        #region Eventi

        public event GameEvent GameEnd;

        private void startTimer_Tick(object sender, EventArgs e)
        {
            startTime = startTime.Subtract(TimeSpan.FromSeconds(1));
            if (startTime.Seconds < 2)
                TextBlockReady.Text = Locale.Strings.GO;
            if (startTime.Seconds < 1)
            {
                // The countdown is finished, the game can start
                startTimer.Tick -= startTimer_Tick;
                CanvasCountdown.Visibility = Visibility.Collapsed;
                UIgameTimer.Start();

                // Generate first schema
                while (!isSchemaValid)
                    GenerateSchema();
                PrepareMirrors();
                PrepareBeamers();
            }
        }

        void imageBeamStart_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            imageBeamStart.MouseLeftButtonDown -= imageBeamStart_MouseLeftButtonDown;
            // Check victory
            int guessedMirrors = 0;
            isSchemaValid = false;
            for (int i = 0; i < mirrors.Count; i++)
            {
                if (mirrors[i].IsRotationCorrect())
                    guessedMirrors++;
            }

            if (guessedMirrors == mirrors.Count)
            {
                // Correct! Add points and increase difficulty
                IncreaseScore(100 + (gameDifficulty * 20));
                correctAnswers++;
                gameDifficulty = correctAnswers / 2;

                // Show correct flux in green
                DrawFlux(Colors.Green, true);

                // Correct answer animation
                imageCorrect.Visibility = Visibility.Visible;
                Animation.FadeOut(imageCorrect, 1000);
            }
            else
            {
                wrongAnswers++;

                // Show correct flux in transparent green
                //DrawFlux(Color.FromArgb(120, 0, 255, 0), true);

                // Show wrong flux in red
                DrawFlux(Colors.Red);

                // Wrong answer animation
                imageWrong.Visibility = Visibility.Visible;
                Animation.FadeOut(imageWrong, 1000);
            }

            // Timer before changing schema
            DispatcherTimer nextSchemaCounter = new DispatcherTimer();
            nextSchemaCounter.Interval = TimeSpan.FromMilliseconds(1000);
            nextSchemaCounter.Tick += new EventHandler(nextSchemaCounter_Tick);
            nextSchemaCounter.Start();
        }

        void nextSchemaCounter_Tick(object sender, EventArgs e)
        {
            DispatcherTimer timer = (DispatcherTimer)sender;
            timer.Tick -= nextSchemaCounter_Tick;
            timer.Stop();
            timer = null;

            // Generate another schema
            while (!isSchemaValid)
                GenerateSchema();
            PrepareMirrors();
            PrepareBeamers();
        }

        private void game_TimeOut(object sender, EventArgs e)
        {
            // Finito il tempo
            GameEventArgs gea = new GameEventArgs();
            gea.reason = GameCloseReason.Timeout;
            gea.score = this.score;
            gea.giuste = correctAnswers;
            gea.sbagliate = wrongAnswers;
            if (GameEnd != null)
                GameEnd(this, gea);
        }

        #endregion
    }
}
